package com.google.code.cisx.client.view;

import com.google.code.cisx.client.DesktopEvent;
import com.google.code.cisx.client.DesktopEvent.DesktopEventType;
import com.google.code.cisx.client.event.EventManager;
import com.google.code.cisx.client.gadgets.GadgetEvent.GadgetEventType;
import com.google.code.cisx.client.model.Gadget;
import com.google.code.cisx.client.model.GadgetClass;
import com.google.code.cisx.client.session.Session;
import com.google.code.cisx.client.session.SessionEvent;
import com.google.code.cisx.client.session.SessionEventListener;
import com.google.code.cisx.client.session.SessionTracker;
import com.google.code.cisx.client.session.SessionEvent.SessionEventType;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;

import java.util.List;

public class DesktopView extends Composite implements DockableListener,
    SessionEventListener<SessionEvent> {

  private TabPanel gadgetTabs = new TabPanel();
  private final DesktopViewListener listener;

  private SessionTracker sessionTracker = SessionTracker.getInstance();
  private HorizontalPanel gadgetsMenu = new HorizontalPanel();
  private VerticalPanel mainPanel;

  public DesktopView(DesktopViewListener ls) {
    this.listener = ls;

    mainPanel = new VerticalPanel();
    initWidget(mainPanel);
    mainPanel.setWidth("100%");
    mainPanel.setHeight("100%");

    gadgetsMenu.setStyleName("GadgetsMenu");
    mainPanel.add(gadgetsMenu);
    mainPanel.setCellHorizontalAlignment(gadgetsMenu, HasHorizontalAlignment.ALIGN_CENTER);

    buildGadgetsMenu();
    
    // create the tab panel
    mainPanel.add(gadgetTabs);
    mainPanel.setCellHeight(gadgetTabs, "100%");
    gadgetTabs.setWidth("100%");
    gadgetTabs.setHeight("100%");

    // create the tabs and pages
    gadgetTabs.add(createPage(), "<div>Navigator</div>", true);
    gadgetTabs.add(createPage(), "<div>Administration</div>", true);

    // select the first tab
    gadgetTabs.selectTab(0);

    EventManager.getInstance().addEventListener(SessionEventType.LOGIN.toString(), this);
    EventManager.getInstance().addEventListener(SessionEventType.LOGOUT.toString(), this);
    EventManager.getInstance().addEventListener(SessionEventType.TIMEOUT.toString(), this);
  }

  public HorizontalPanel createPage() {
    HorizontalPanel page = new HorizontalPanel();
    page.setStyleName("GadgetPage");
    page.setWidth("100%");
    page.setHeight("100%");
    page.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
    createColumn(page, 0);
    createColumn(page, 1);
    createColumn(page, 2);
    return page;
  }

  public void createColumn(HorizontalPanel page, int columnNumber) {
    // create the column with a FlowPanel
    FlowPanel column = new FlowPanel();
    column.setStyleName("GadgetColumn");
    page.add(column);
    page.setCellWidth(column, "33%");
    page.setCellHeight(column, "100%");
    column.setHeight("100%");
    DockableWidget.addContainer(column);
  }

  public HorizontalPanel getCurrentPage() {
    return (HorizontalPanel) gadgetTabs.getDeckPanel().getWidget(
        gadgetTabs.getDeckPanel().getVisibleWidget());
  }

  public void insertGadget(Gadget gadget) {
    FlowPanel column = (FlowPanel) getCurrentPage().getWidget(0);
    insertGadget(column, gadget);
    gadget.setGadgetListener(listener);
    // listener.onInterfaceChange();
    EventManager.getInstance().dispatchEvent(
        new DesktopEvent(gadget, DesktopEventType.DESKTOP_STATE_CHANGED.toString()));
  }

  protected void insertGadget(FlowPanel column, Gadget gadget) {
    GadgetContainerView gadgetContainer = new GadgetContainerView(gadget);

    // setup GadgetContainer to listen to GadgetEvents
    EventManager.getInstance().addEventListener(GadgetEventType.GADGET_INITIALIZED.toString(),
        gadgetContainer);
    EventManager.getInstance().addEventListener(GadgetEventType.GADGET_MAXIMIZED.toString(),
        gadgetContainer);
    EventManager.getInstance().addEventListener(GadgetEventType.GADGET_CLOSED.toString(),
        gadgetContainer);

    DockableWidget dw = new DockableWidget(gadgetContainer);
    column.add(dw);
    dw.addDockableListener(this);
  }

  public void setLayoutFromString(String layout) {
    List classes = GadgetClass.getClasses();
    Document document = XMLParser.parse(layout);
    Element element = document.getDocumentElement();
    NodeList pages = element.getElementsByTagName("Page");
    for (int i = 0; i < pages.getLength(); i++) {
      HorizontalPanel page = (HorizontalPanel) gadgetTabs.getDeckPanel().getWidget(i);
      Element pageElement = (Element) pages.item(i);
      NodeList columns = pageElement.getElementsByTagName("Column");
      for (int j = 0; j < columns.getLength(); j++) {
        FlowPanel column = (FlowPanel) page.getWidget(j);
        Element columnElement = (Element) columns.item(j);
        NodeList gadgets = columnElement.getElementsByTagName("Gadget");
        for (int k = 0; k < gadgets.getLength(); ++k) {
          Element gadgetElement = (Element) gadgets.item(k);
          String name = gadgetElement.getAttribute("name");
          for (int l = 0; l < classes.size(); ++l) {
            GadgetClass gc = (GadgetClass) classes.get(l);
            if (name.compareTo(gc.getName()) == 0) {
              Gadget gadget = gc.newGadget();
              gadget.fromXML(gadgetElement);
              insertGadget(column, gadget);
              l = classes.size();
            }
          }
        }
      }
    }
  }

  public String getLayoutAsString() {
    Document document = XMLParser.createDocument();
    Element element = document.createElement("Desktop");
    document.appendChild(element);
    int pageCount = gadgetTabs.getDeckPanel().getWidgetCount();
    for (int i = 0; i < pageCount; ++i) {
      Element pageElement = element.getOwnerDocument().createElement("Page");
      element.appendChild(pageElement);
      HorizontalPanel page = (HorizontalPanel) gadgetTabs.getDeckPanel().getWidget(i);
      int columnCount = page.getWidgetCount();
      for (int j = 0; j < columnCount; j++) {
        FlowPanel column = (FlowPanel) page.getWidget(j);
        Element columnElement = element.getOwnerDocument().createElement("Column");
        pageElement.appendChild(columnElement);
        int gadgetCount = column.getWidgetCount();
        for (int k = 0; k < gadgetCount; ++k) {
          Element gadgetElement = element.getOwnerDocument().createElement("Gadget");
          columnElement.appendChild(gadgetElement);
          DockableWidget dockacbleWidget = (DockableWidget) column.getWidget(k);
          GadgetContainerView gadgetContainer = (GadgetContainerView) dockacbleWidget.getWidget();
          gadgetContainer.getGadget().toXML(gadgetElement);
        }
      }
    }
    return document.toString();
  }

  public void onDocked(Widget widget) {
    // listener.onInterfaceChange();
    EventManager.getInstance().dispatchEvent(
        new DesktopEvent(widget, DesktopEventType.DESKTOP_STATE_CHANGED.toString()));
  }

  /**
   * SessionEvent handler
   */
  public void onEvent(SessionEvent event) {
    // we don't check for specific type of session event
    // we refresh the Gadgets Menu on every SessionEvent, no matter what type.
    refreshGadgetsMenu();
  }

  /**
   * Rebuilds the Gadgets Menu, adding and removing elements as appropriate.
   */
  private void refreshGadgetsMenu() {
    // add gadgets
    List classes = GadgetClass.getClasses();
    for (int i = 0; i < classes.size(); ++i) {
      final GadgetClass gadgetClass = (GadgetClass) classes.get(i);
      final Hyperlink gadgetLink = new Hyperlink(gadgetClass.getName(), "");
      gadgetLink.addClickListener(new ClickListener() {
        public void onClick(Widget sender) {
          insertGadget(gadgetClass.newGadget());
          gadgetsMenu.remove(gadgetLink); // remove the link from the gadgets
          // menu since multiple instances not allowed to be displayed.
        }
      });
      // Display secured/public Gadgets if a user session is active/inactive.
      Session session = sessionTracker.getSession();
      if (null == session && !gadgetClass.isSecured())
        gadgetsMenu.add(gadgetLink);
      if (null != session)
        gadgetsMenu.add(gadgetLink);
    }
  }

  /**
   * @param mainPanel
   */
  private void buildGadgetsMenu() {
    // add gadgets
    List classes = GadgetClass.getClasses();
    gadgetsMenu.add(new Label("Taskbar : "));
    for (int i = 0; i < classes.size(); ++i) {
      final GadgetClass gadgetClass = (GadgetClass) classes.get(i);
      final Hyperlink gadgetLink = new Hyperlink(gadgetClass.getName(), "");
      gadgetLink.addClickListener(new ClickListener() {
        public void onClick(Widget sender) {
          insertGadget(gadgetClass.newGadget());
          gadgetsMenu.remove(gadgetLink); // remove the link from the gadgets
          // menu since multiple instances not allowed to be displayed.
        }
      });

      // Display secured/public Gadgets if a user session is active/inactive.
      Session session = sessionTracker.getSession();
      if (null == session && !gadgetClass.isSecured())
        gadgetsMenu.add(gadgetLink);
      if (null != session && session.isActive())
        gadgetsMenu.add(gadgetLink);
    }
  }

}
